﻿
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;

namespace Demention
{
    [DisallowMultipleComponent]
    public class DementionCameral:MonoBehaviour
    {
        public RecordSettings RecordSettings;
        private int _index = 0;
        private Camera _camera;
        private Animator _animator;
        public GameObject _target;
        private bool _needCut = false;
        private List<Texture2D> texture2Ds;

        private void Start()
        {
            int layer  = LayerMask.NameToLayer("RenderTarget");
            SetLayer(layer,_target.transform);
            _camera = GetComponent<Camera>();
            //------------
            _camera.depthTextureMode = DepthTextureMode.Depth;
            texture2Ds = new List<Texture2D>();
            SetMatial(RecordSettings);
            StartCoroutine(RecordCortinue());
        }

        private void OnEnable()
        {
            AddNecessaryComponent();
        }

        private void Reset()
        {
            DementionPreview dementionPreview = GetComponent<DementionPreview>();
            if (dementionPreview ==  null)
            {
                dementionPreview = gameObject.AddComponent<DementionPreview>();
            }
            dementionPreview.RecordSettings = RecordSettings;
        }

        private void SetLayer(int layer,Transform transform) 
        {
            for (int i = 0; i < transform.childCount; i++)
            {
                transform.GetChild(i).gameObject.layer = layer;
                SetLayer( layer, transform.GetChild(i));
            }
        }

        private void AddNecessaryComponent() 
        {
            if (_target.GetComponent<Animator>() == null)
            {
                _animator = _target.AddComponent<Animator>();
            }
            if (_target.GetComponent<Animation>() != null)
            {
                _target.GetComponent<Animation>().playAutomatically = false;
            }
            _animator = _target.GetComponent<Animator>();
            _animator.enabled = false;
            for (int i = 0; i < RecordSettings._animationClips.Length; i++)
            {
                AnimationClip clip = RecordSettings._animationClips[i];
                AnimationClip[] clips = _animator.runtimeAnimatorController.animationClips;
                if (clips.Where(cl => cl.name == clip.name).FirstOrDefault() == null)
                {
                    AnimatorState state = ((AnimatorController)_animator.runtimeAnimatorController).layers[0].stateMachine.AddState(clip.name);
                    state.motion = clip;
                }
            }
        }

        private IEnumerator RecordCortinue() 
        {
            for (int i = 0; i < 30; i++)
            {
                yield return null;
            }

            foreach (AnimationClip item in _animator.runtimeAnimatorController.animationClips)
            {
                texture2Ds.Clear();
                if (RecordSettings._animationClips.Where(rs => rs.name == item.name).FirstOrDefault() != null)
                {
                    item.legacy = false;
                    item.SampleAnimation(_target, 0);
                    _needCut = true;
                    yield return null;

                    float length = item.length;
                    float recordTime = length * RecordSettings._frameRate;

                    float step = 0; 
                    for (float j = 0; j < length; j += Time.deltaTime)
                    {
                        if (j > step)
                        {
                            item.SampleAnimation(_target, j);
                            _needCut = true;
                            step += 1f / RecordSettings._frameRate;
                            Debug.Log(step);

                        }
                        yield return null;
                    }
                    item.SampleAnimation(_target, length);
                    _needCut = true;
                    yield return null;
                }
                Write(item.name);
            }

#if UNITY_EDITOR
            EditorApplication.isPlaying = false;
#endif
        }
    
        private Texture2D toTexture2D(RenderTexture rTex)
        {
            Texture2D tex = new Texture2D(rTex.width, rTex.height, TextureFormat.ARGB32, false);
            RenderTexture.active = rTex;
            tex.ReadPixels(new Rect(0, 0, rTex.width, rTex.height), 0, 0);
            tex.Apply();
            return tex;
        }

        private void OnRenderImage(RenderTexture source, RenderTexture destination)
        {
            if (!_needCut)
            {
                return;
            }
            RenderTexture texture = source;// _camera.targetTexture;
            RenderTexture renderTexture;
            RenderTexture renderTextureTemp = new RenderTexture(texture.width, texture.height, 0);
            Graphics.Blit(texture, renderTextureTemp, RecordSettings._material[0]);
            for (int i = 1; i < RecordSettings._material.Length; i++)
            {
                renderTexture = renderTextureTemp;
                renderTextureTemp = new RenderTexture(texture.width, texture.height, 0);
                Graphics.Blit(renderTexture, renderTextureTemp, RecordSettings._material[i]);
            }
            _needCut = false;
            Texture2D texture2D = toTexture2D(renderTextureTemp);

            texture2Ds.Add(texture2D);
        }

        private void Write(string animaName) 
        {
            for (int i = 0; i < texture2Ds.Count; i++)
            {
                byte[] bytes = texture2Ds[i].EncodeToPNG();
                string directory = Path.Combine(this.RecordSettings._path, animaName);
                string fileName = Path.Combine(directory , _index + ".png");
                if (File.Exists(fileName))
                {
                    File.Delete(fileName);
                }
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }
                FileStream fileStream = File.Create(fileName);
                fileStream.Write(bytes, 0, bytes.Length);
                fileStream.Flush();
                fileStream.Close();
                _index++;
                DestroyImmediate(texture2Ds[i]);
            }
        }

        internal void SetMatial(RecordSettings recordSettings) 
        {
            for (int i = 0; i < recordSettings._material.Length; i++)
            {
                if (RecordSettings._material[i].shader.name == "Hidden/Mosaic")
                {
                    RecordSettings._material[i].SetInt("_MainTxtWidth",Screen.width);
                    RecordSettings._material[i].SetInt("_MainTxtHeight", Screen.height);
                }
            }
        }
    }
}
